// Drummer
// by Andrea Bianchi
// andreabianchi.alsoplantsfly.com

/*
 Copyright (C) 2009, Andrea Bianchi
 
 This program is free software; you can redistribute it and/or
 modify it under the terms of the GNU General Public License
 as published by the Free Software Foundation; either version 2
 of the License, or (at your option) any later version.
 
 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 along with this program; if not, write to the Free Software
 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
*/


#include "networkManager.h"
#include <stdlib.h>
#include <sstream>
using namespace DS;


NetworkManager* NetworkManager::getInstance()
{	
	static NetworkManager histnace;
	return &histnace;
}


bool NetworkManager::initConnection()
{
	PA_Print(UPPER_SCREEN, "Initializing Wifi... please wait\n");
	if (firstTime_){
		PA_InitWifi();	
		firstTime_=false;
	}
 	
	if (PA_ConnectWifiWFC())
	{
		PA_Print(UPPER_SCREEN, " Connected\n");	
	} else {
		PA_Print(UPPER_SCREEN, " Could not connect");
		return false;
	}

	// get server number 
	std::string input;
	initKeyboard();

	do 
	{
		PA_ClearTextBg(LOWER_SCREEN); 
		input= getKeyboardInput("Enter IP address:");
	}while (!isValidIp(input));
	serverName_= input;
	PA_Print(UPPER_SCREEN, "IP: %s\n",serverName_.c_str());

	//get server port
	do 
	{
		PA_ClearTextBg(LOWER_SCREEN); 
		input= getKeyboardInput(" Enter Port number:");
	} while (!isNumber(input));

	port_= atoi(input.c_str());
	PA_Print(UPPER_SCREEN, "PORT: %s\n\n",input.c_str());
	closeKeyboard();


	// attempt to open socket 3 times
	u8 attempt=1;
	do {
		PA_Print(UPPER_SCREEN, "Trying to open socket, attempt %d", attempt);
		if (attempt++ == 3){
			PA_Print(UPPER_SCREEN, "Socket open failed");
			return false;
		}

	} while (!PA_InitSocket(&socket_, const_cast<char*>(serverName_.c_str()), port_, PA_NORMAL_TCP));
		
	PA_Print(UPPER_SCREEN, "Connected to server %s at port %d", serverName_.c_str(), input.c_str());
	
	return true;
}

bool NetworkManager::disconnect()
{
	// Image on Background

	// Text
	u8 ret= shutdown(socket_, 0) || closesocket(socket_) || Wifi_DisconnectAP();

	if (ret==1){
		PA_Print(UPPER_SCREEN, "A problem occurred while disconnecting");
		return false;		
	}

	PA_Print(UPPER_SCREEN, "Disconnected");
	return true;
}


void NetworkManager::initKeyboard()
{
	PA_InitKeyboard(KEYBOARD_LAYER); 
	PA_KeyboardIn(25, 95); 
}

void NetworkManager::closeKeyboard()
{
	PA_KeyboardOut();
}

std::string NetworkManager::getKeyboardInput(char* message){

	PA_OutputSimpleText(LOWER_SCREEN, 5, 0, message); 
	std::string input;

	u8 nletter = 0;
	char letter = 0; 

	// Infinite loop to keep the program running
	while (1)
	{
		letter = PA_CheckKeyboard();

		if ((letter >='0' && letter<='9') || (letter=='.')) 
		{ 
			// there is a new letter
			if (nletter<BUFFER_SIZE){
				input+= letter;
				nletter++;
			}

		} else if (letter == '\n'){ // Enter pressed
			// minimum check check and return
			if (nletter>0){
				return input;
			}
		}

		else if ((letter == PA_BACKSPACE) && nletter>0) { // Backspace pressed
			nletter--;
			PA_OutputSimpleText(LOWER_SCREEN, 5, 5, "                  ");
			input= input.substr(0, nletter);
		}

		PA_OutputSimpleText(LOWER_SCREEN, 5, 5, input.c_str()); // Write the text	
		PA_WaitForVBL();
	}
}

// a slow method that checks if we have a reasonably valid input (not guaranteeed though)
bool NetworkManager::isValidIp (std::string ip)
{
	std::string temp;
	u8 dots=0;
	for (u8 i=0; i<ip.size();++i)
	{
		if (ip[i]=='.' && isNumber(ip[i-1]) &&  isNumber(ip[i+1]))
		{
			dots++;
		}else{
			if (!isNumber(ip[i])) return false;
		}
	}
	return dots==3;
}

// a slow method that checks if we have a valid input
bool NetworkManager::isNumber (std::string val)
{
	if (val.size()==0) return false;
	for (u8 i=0; i<val.size();++i)
	{
		if (val[i]<'0' || val[i]>'9') return false;
	}
	return true;
}

bool NetworkManager::isNumber (char val)
{
	return val>='0' && val<='9';
}



void NetworkManager::sendMessage (std::string message)
{
	send(socket_, message.c_str(), message.size(), 0);
}


void NetworkManager::sendMessage (DrumPart instrument)
{
	sendMessage(instrument, 0);	
}

void NetworkManager::sendMessage (DrumPart instrument, u8 velocity)
{
	std::string msg="";

	switch(instrument)
	{
	case SILENCE: msg="0"; break;
	case BASSDRUM1: msg="1"; break;
	case BASSDRUM2: msg="2"; break;
	case HIHAT1:    msg="3"; break;
	case HIHAT2:    msg="4"; break;
	case SNARE1:    msg="5"; break;
	case SNARE2:    msg="6"; break;
	case CRASH1:    msg="7"; break;
	case CRASH2:    msg="8"; break;
	case TOM1:  msg="9"; break;
	case TOM2:  msg="10"; break;
	case TOM3:  msg="11"; break;
	case TOM4:  msg="12"; break;
	default: msg="13"; break;
	}

	if (msg.size()==0) return; // nothing to send

	std::string vel="";

	std::ostringstream stm;
	stm << (int)(velocity);
	vel= stm.str();
	
	NetworkManager::getInstance()->sendMessage(msg+";"+vel);
}